package TAIC.flicker.LM ;
import java.nio.channels.*;
import java.util.*;
import java.io.* ;

public class ImageRetrieve {
	public static final int RETRIVE_IMAGE = 35 ; 
	public static final int MAX_CLASS = 100;
	public static int IMAGE_PER_WORD = 8 ; 
	public static final int MAX_GET_IMAGE_THREAD = 50 ;
	public static Stemmer stemmer = new Stemmer () ;
	int totalKeys = 10 ;
	String configPath ; 
	String path [] = new String [ MAX_CLASS ] ;
	String testImage [] = new String [ MAX_CLASS ] ; 
	String classNames [] = new String [ MAX_CLASS ] ; 
	String imageDataPath = "";
	int classes ;
	public String modelFileName;
	public String imageModelFile ; 
	public String dictFile ;
	public boolean labelOnly ; 
	HashMap < String, String [] >wordMapping = new HashMap < String, String [] > () ;
	HashMap < String, double [] > dict = new HashMap < String, double[] > () ; 
//	double nambda ; 
	
	public ImageRetrieve ( String config, String name, String dictFile , String imageModel, boolean flag ) {
		configPath = config ;
		modelFileName = name ;
		this.dictFile = dictFile;
		this.imageModelFile = imageModel ;
		labelOnly = flag ; 
	}

	static public void main ( String argu [] ) throws Exception {
		boolean flag = false ; 
		if ( argu.length < 4 ) {
			System.out.println ( "Please input arguments: the path of config file, the output model file, " + 
					"imageWord Dict and the output ImageFeature modelfile" ) ;
			System.out.println ( "Or use these arguments: the path of config file, the output model file, " + 
			"imageWord Dict, the output ImageFeature modelfile and LABEL_ONLY" ) ;
			return ; 
		}
		if ( argu.length > 4 ) flag = true ;
		(new  ImageRetrieve  ( argu [ 0 ], argu[ 1 ], argu[ 2 ], argu[ 3 ], flag )).run();
	}
	
	public void run () throws Exception {
		int i , j  ;
		BayesInDoc bayesianModel ; 
		/////////////   read from query2.txt to get information ///////////////////////////////
		preprocess () ;
		
		////////////////    to get key words from Bayes and IG. Results are also stored in KeyWord.txt  //////////////////
		bayesianModel = new BayesInDoc ( "..\\FlickerWords.txt", totalKeys ) ;
		ArrayList < KeyWord > result = ( bayesianModel ).getKey();
		System.out.println ( "Bayesian Statical Calculation Complete" ) ;
		
		//////// Get Images from \\Poseidon\Team\DataSet\Data\FlickrAnnotations\FlickrAnno  using mapping wordMapping.txt //////////
		////////  and generate the final image courpus ImageCourpus and word2Image.txt  /////////
		PrintStream fout = null ;
		PrintStream fout1 = null ;		
		
		fout = new PrintStream ( new File ( "ImageCorpus.txt" ) ) ;
		fout1 = new PrintStream ( new File ( "IP\\word2image.txt" ) ) ;
		
		for ( i = 0 ; i < result.size() ; i ++ ) { 
			String [] images = wordMapping.get( result.get(i).word);
			for ( j = 0 ; j < images.length ; j ++ ) 
				fout.println ( result.get(i).classNo + " " + ( i % totalKeys ) + " " + imageDataPath + images[ j ] + ".jpg") ;
			//System.out.printf ( "class %d: there are %d images for word \"%s\"\n", result.get(i).classNo, images.length, result.get(i).word ); 
		}
		
		fout1.println ( classes + " " + totalKeys ) ; 
		for ( i = 0 ; i < result.size() ; i ++ ) 
			fout1.println ( result.get(i).classNo + " " + (i%totalKeys)+ " " +  result.get(i).prob  ) ;
		//   word, classNo , wordNo , prob
		//	fout1.println ( nambda ) ; 
		fout1.close() ;

		for ( i = 0 ; i < classes ; i ++ ) {
			Scanner scanner = new Scanner ( new File ( testImage  [ i ] + "index.txt" ) ) ; 
			//System.out.println ( testImage[ i ] + " " + i  ) ;
			while ( scanner.hasNextLine () ) {
				String s = testImage[ i ] + scanner.nextLine ().trim() ; 
				if ( (new File(s)).exists() ) fout.println ( (classes + i) + " 0 "  + s ) ; 
			}
		}
		fout.close() ;
		
		
		////////////////  output the model to a file   //////////////////
		fout = new PrintStream ( new File ( modelFileName ) ) ;
		int totalWords = bayesianModel.inverseMap.size() ; 
		fout.print ( "Word_List: " + totalWords ) ;
		for ( i = 0 ; i < totalWords ; i ++ ) { 
			if ( i % 50 == 0 ) fout.println () ;
			fout.print ( " " + bayesianModel.inverseMap.get( i )) ; 
		}
		
		fout.println ( "\r\n\r\nTotal_Classes: " + classes ) ; 
		for ( i = 0 ; i < classes ; i ++ ) {
			fout.printf ( "\r\n//////////Model_For_Class_%d//////////////\r\n", i ) ;
			fout.println( "P(c): " +  bayesianModel.P_c [ i ] ) ;
			fout.print ( "P(w|c):") ;
			for ( j = 0 ; j < totalWords ; j ++ ) {
				if ( j  % 50 == 0 ) fout.println () ;
				fout.printf ( " %.8f" , bayesianModel.P_c_w [ i ][ j ]) ; 					
			}
			fout.println () ;
		}
		
		///////////////    generate the imageModel  //////////////////////
		Scanner scanner = new Scanner ( new File ( dictFile ) ) ;
		while(  scanner.hasNext() ) { 
			String word = scanner.next(); 
			double [] p = new double [ 800 ] ;
			for ( i = 0 ; i < 800 ; i ++ ) p [ i ] = scanner.nextDouble() ;
			dict.put( word,  p ) ;
		}
		scanner.close() ;
		
		fout = new PrintStream ( new File ( imageModelFile ) ) ;
		fout.println ( "Total_Classes: " + classes ) ;
		for ( i = 0 ; i < classes ; i ++ ) {
			double [] p = new double [ 800 ] ;
			if ( ! labelOnly ) { 
				for ( j = 0; j < totalWords; j ++ ) {
					String word = bayesianModel.inverseMap.get( j ) ;
					double [] q = dict.get( word ) ;
					for ( int k = 0 ; k < 800; k ++ ) p [ k ] += bayesianModel.P_c_w[i][j] * q [ k ] ; 
				}
			}
			else {
				String word = classNames [ i ] ;
				double [] q = dict.get( word ) ;
				if ( q == null ) 
					for ( int k = 0 ; k < 800 ; k++ ) p [ k ] = 1.0 / 800 ; 
				else p = q ; 
			}
			for ( j = 0 ; j < 800 ; j ++ ) fout.printf( " %.8f", p [ j ] ) ;
			fout.println(); 
		}
		fout.close() ;
		
		System.out.println ( "All should be done had been done, Exit!" ) ;
	}
	
    public void preprocess () throws Exception {
		int i , docs ;
		
		Scanner scanner = new Scanner ( new File ( configPath ) );
		scanner.next() ;
		totalKeys = scanner.nextInt () ; scanner.next () ;
		IMAGE_PER_WORD = scanner.nextInt() ; scanner.nextLine () ; 
	//	nambda = scanner.nextDouble() ; 
		
		imageDataPath = scanner.nextLine ().trim() ;
        classes = scanner.nextInt () ; scanner.nextLine () ; 
		for ( i = 0 ; i < classes ; i ++ ) classNames [ i ] = stemmer.stem( scanner.nextLine ().trim () ) ; 
        for ( i = 0 ; i < classes ; i ++ ) 
            path [ i ] = scanner.nextLine().trim() ;
		for ( i = 0 ; i  < classes ; i ++ ) 
			testImage [ i ] = scanner.nextLine().trim() ; 
			
		docs = 0 ; 
		PrintStream fout = new PrintStream ( new File ( "temp.txt" ) ) ; 		
		fout.println ( classes ) ;
		for ( i = 0 ; i < classes ; i ++ ) {
			scanner = new Scanner ( new File ( path [ i ] + "index.txt" ) ) ;
			while ( scanner.hasNextLine () ) {
				fout.println ( i + " " + path [ i ] + scanner.nextLine () ) ;
				docs ++ ; 
			}
		}
		
		fout.close () ;
		
		// create the word to image mapping 
		scanner = new Scanner ( new File ( "..\\wordMapping.txt" )) ;
		String[] images ; 
		while ( scanner.hasNext() ) {
			String word = stemmer.stem( scanner.next() );
			int len = scanner.nextInt() ;
			String [] oldImages = null ;
			
			if ( (oldImages = wordMapping.get(word)) == null ) images = new String  [ len ] ; 
			else {
				images = new String  [ oldImages.length +  len ] ;
				for ( i = 0; i < oldImages.length ; i ++ ) images [ len + i ] = oldImages [ i ] ;
			}
			
			for ( i = 0 ; i < len ; i ++ ) images [ i ]	 = scanner.next() ;
			wordMapping.put ( word, images ); 
		}
	}
			
	int toInt ( double d ) {
		return Math.round((float)d);
	}
	
	public static boolean copyFile( String a , String b ) //  Source and Destination
    {
    	boolean done= true ;
		File in = new File ( a );
		File out = new File ( b ) ;
		FileChannel inChannel = null;
		FileChannel outChannel = null;
        try {
    	
        inChannel = new
            FileInputStream(in).getChannel();
        outChannel = new
            FileOutputStream(out).getChannel();
            inChannel.transferTo(0, inChannel.size(),
                    outChannel);
        } 
        catch (IOException e) {
            //e.printStackTrace () ;
            done =  false ;
        }
        return done ;
    }	
} 